#!/usr/bin/env python3
"""
Final Bug Fix Generation Script
Regenerates all C++ files with bugs #1 and #3 fixed
"""

import json
import sys
from pathlib import Path

# Add orchestrator to Python path
sys.path.insert(0, str(Path(__file__).parent.parent.parent / "cpp-orchestrator" / "src"))

from orchestrator.codegen.emitter import CppEmitter
from orchestrator.ir.nodes import (
    ClassDeclaration,
    ConstructorDeclaration,
    FieldDeclaration,
    MethodDeclaration,
    PropertyDeclaration,
    Parameter,
)


def json_to_class_declaration(data: dict) -> ClassDeclaration:
    """Convert JSON dict to ClassDeclaration IR node"""

    # Convert fields
    fields = []
    for field_data in data.get("fields", []):
        field = FieldDeclaration(
            name=field_data["name"],
            field_type=field_data["field_type"],
            modifiers=field_data.get("modifiers", []),
            initializer=field_data.get("initializer"),
            is_readonly=field_data.get("is_readonly", False),
            is_const=field_data.get("is_const", False),
            metadata=field_data.get("metadata", {}),
            source_file=field_data.get("source_file"),
            line_number=field_data.get("line_number"),
        )
        fields.append(field)

    # Convert properties
    properties = []
    for prop_data in data.get("properties", []):
        prop = PropertyDeclaration(
            name=prop_data["name"],
            property_type=prop_data["property_type"],
            modifiers=prop_data.get("modifiers", []),
            has_getter=prop_data.get("has_getter", False),
            has_setter=prop_data.get("has_setter", False),
            getter_body=prop_data.get("getter_body"),
            setter_body=prop_data.get("setter_body"),
            is_auto_property=prop_data.get("is_auto_property", False),
            initializer=prop_data.get("initializer"),
            metadata=prop_data.get("metadata", {}),
            source_file=prop_data.get("source_file"),
            line_number=prop_data.get("line_number"),
        )
        properties.append(prop)

    # Convert methods
    methods = []
    for method_data in data.get("methods", []):
        # Convert parameters
        params = []
        for param_data in method_data.get("parameters", []):
            param = Parameter(
                name=param_data["name"],
                param_type=param_data["param_type"],
                default_value=param_data.get("default_value"),
            )
            params.append(param)

        method = MethodDeclaration(
            name=method_data["name"],
            return_type=method_data["return_type"],
            parameters=params,
            modifiers=method_data.get("modifiers", []),
            body=method_data.get("body"),
            is_abstract=method_data.get("is_abstract", False),
            is_virtual=method_data.get("is_virtual", False),
            is_override=method_data.get("is_override", False),
            is_static=method_data.get("is_static", False),
            metadata=method_data.get("metadata", {}),
            source_file=method_data.get("source_file"),
            line_number=method_data.get("line_number"),
        )
        methods.append(method)

    # Convert constructors
    constructors = []
    for ctor_data in data.get("constructors", []):
        params = []
        for param_data in ctor_data.get("parameters", []):
            param = Parameter(
                name=param_data["name"],
                param_type=param_data["param_type"],
                default_value=param_data.get("default_value"),
            )
            params.append(param)

        ctor = ConstructorDeclaration(
            name=data["name"],
            parameters=params,
            modifiers=ctor_data.get("modifiers", []),
            body=ctor_data.get("body"),
            metadata=ctor_data.get("metadata", {}),
            source_file=ctor_data.get("source_file"),
            line_number=ctor_data.get("line_number"),
        )
        constructors.append(ctor)

    # Create ClassDeclaration
    class_node = ClassDeclaration(
        name=data["name"],
        namespace=data.get("namespace", ""),
        modifiers=data.get("modifiers", []),
        base_types=data.get("base_types", []),
        fields=fields,
        properties=properties,
        methods=methods,
        constructors=constructors,
        is_abstract=data.get("is_abstract", False),
        is_sealed=data.get("is_sealed", False),
        is_static=data.get("is_static", False),
        metadata=data.get("metadata", {}),
        source_file=data.get("source_file"),
        line_number=data.get("line_number"),
    )

    return class_node


def main():
    print("="*60)
    print("Final C++ Code Regeneration (Bugs #1 & #3 Fixed)")
    print("="*60)

    base_dir = Path(__file__).parent.parent
    ir_dir = base_dir / "03-ir-output"
    output_base = Path(__file__).parent

    # Map of IR files to generate
    files_to_generate = {
        "C5": ["ArrayList-ir.json", "HashSet-ir.json"],
        "DelegateTransform": ["DelegateTransform-ir.json", "DelegateTransformTests-ir.json"],
        "DotNetCSharpLinqByExample": ["Pet-ir.json", "Joins-ir.json"],
        "RobloxAPI": ["Group-ir.json", "GroupRole-ir.json", "HttpHelper-ir.json",
                      "Outfit-ir.json", "SearchAPI-ir.json"],
    }

    emitter = CppEmitter()
    total_generated = 0

    for repo_name, ir_files in files_to_generate.items():
        print(f"\n{repo_name}:")
        repo_output_dir = output_base / repo_name
        repo_output_dir.mkdir(parents=True, exist_ok=True)

        for ir_file in ir_files:
            ir_path = ir_dir / repo_name / ir_file

            if not ir_path.exists():
                print(f"  ⚠ NOT FOUND: {ir_file}")
                continue

            try:
                # Load IR
                with open(ir_path, 'r') as f:
                    data = json.load(f)

                class_node = json_to_class_declaration(data)

                # Generate C++ code
                header_path, source_path = emitter.emit_class(class_node, repo_output_dir)

                print(f"  ✓ Generated: {header_path.name} & {source_path.name}")
                total_generated += 2

            except Exception as e:
                print(f"  ✗ ERROR generating {ir_file}: {e}")

    print("\n" + "="*60)
    print(f"Total files generated: {total_generated}")
    print(f"Output directory: {output_base}")
    print("="*60)


if __name__ == "__main__":
    main()
